import * as Cesium from "cesium";
import * as dat from "dat.gui";

export default class HighFogEffect {
  constructor(viewer, options) {
    if (!viewer) throw new Error("no viewer object!");
    options = options || {};

    this.viewer = viewer;
    this.visibility = Cesium.defaultValue(options.visibility, 0.5);
    this.color = Cesium.defaultValue(
      options.color,
      new Cesium.Color(0.8, 0.82, 0.84)
    );
    this.minHeight = Cesium.defaultValue(options.minHeight, 0.0);
    this.maxHeight = Cesium.defaultValue(options.maxHeight, 6000000.0);
    this._show = Cesium.defaultValue(options.show, true);

    this.init();
  }

  init() {
    this.viewer.camera.setView({
      destination: Cesium.Cartesian3.fromDegrees(114.1, 25.1, 4000),
      orientation: {
        pitch: -0.6,
      },
    });
    this.fogStage = new Cesium.PostProcessStage({
      name: "czm_realHeightFog",
      fragmentShader: this.fog(),
      uniforms: {
        visibility: () => this.visibility,
        fogColor: () => this.color,
        minHeight: () => this.minHeight,
        maxHeight: () => this.maxHeight,
        u_earthRadiusOnCamera: () =>
          Cesium.Cartesian3.magnitude(this.viewer.camera.positionWC) -
          this.viewer.camera.positionCartographic.height,
      },
    });

    this.viewer.scene.postProcessStages.add(this.fogStage);
    this.addGui(this.fogStage.uniforms);
  }

  addGui(uniformMap) {
    const gui = new dat.GUI();
    // gui.add(this, "visibility", 0.0, 1.0).step(0.1).name("雾浓度");
    // // gui.addColor(this, "color").name("雾颜色");
    // gui.add(this, "minHeight", 0.0, 1000.0).step(50).name("起始雾高");
    // gui.add(this, "maxHeight", 6000000.0, 6500000.0).step(10).name("最大雾高");
    // gui
    //   .add(this, "_show")
    //   .name("显示雾效")
    //   .onChange((v) => this.show(v));
  }

  show(visible) {
    this._show = visible;
    if (this.fogStage) this.fogStage.enabled = visible;
  }

  destroy() {
    if (this.viewer && this.fogStage) {
      this.viewer.scene.postProcessStages.remove(this.fogStage);
    }
    if (this._terrainInterval) clearInterval(this._terrainInterval);
  }

  fog() {
    return `
    precision mediump float;
    uniform sampler2D colorTexture;
    uniform sampler2D depthTexture;
    uniform float visibility;
    uniform vec3 fogColor;
    uniform float minHeight;
    uniform float maxHeight;
    uniform float u_earthRadiusOnCamera;

    in vec2 v_textureCoordinates;
    out vec4 myColor;

    vec4 getWorldCoordinate(sampler2D depthTexture, vec2 texCoords) {
        float depth = czm_unpackDepth(texture(depthTexture, texCoords));
        vec4 eyeCoordinate = czm_windowToEyeCoordinates(gl_FragCoord.xy, depth);
        eyeCoordinate = eyeCoordinate / eyeCoordinate.w;
        vec4 worldCoordinate = czm_inverseView * eyeCoordinate;
        worldCoordinate = worldCoordinate / worldCoordinate.w;
        return worldCoordinate;
    }

    float getRoughHeight(vec4 worldCoordinate, float earthRadiusOnCamera) {
        float disToCenter = length(vec3(worldCoordinate));
        return disToCenter - earthRadiusOnCamera;
    }

    float getViewDistance(vec4 worldCoordinate) {
        vec3 cameraPosition = czm_inverseView[3].xyz; // 获取相机世界坐标
        return length(worldCoordinate.xyz - cameraPosition); // 计算相机与当前像素的距离
    }

    float getPixelHeight(vec4 worldCoordinate, float earthRadiusOnCamera) {
        return max(length(vec3(worldCoordinate)) - earthRadiusOnCamera, 0.0);
    }

    float sampleHeightFog(float minH, float maxH, float heightAboveGround) {
        return 1.0 - smoothstep(minH, maxH, heightAboveGround);
    }

    // 简单的线性高度雾
    float sampleLinearHeightFog(float fogHeight, float pixelHeight) {
        float fog = clamp(fogHeight / pixelHeight - 1.0, 0.0, 1.0);
        return fog;
    }

    // 线性欧式深度雾，根据距离在两个阈值间线性插值雾的强度，近处无雾，远处全雾
    float sampleLinearFog(float minDistance, float maxDistance, float distance)
    {
        float startDistance = minDistance;
        float startValue = 0.0;
        float endDistance = maxDistance;
        float endValue = 1.0;
        float t = clamp((distance - startDistance) / (endDistance - startDistance), 0.0, 1.0);
        return mix(startValue, endValue, t);
    }

    void main(void) {
        vec4 origncolor = texture(colorTexture, v_textureCoordinates);
        vec4 positionWC = getWorldCoordinate(depthTexture, v_textureCoordinates);
        float pixelHeight = getRoughHeight(positionWC, u_earthRadiusOnCamera);
        // float pixelHeight = getPixelHeight(positionWC, u_earthRadiusOnCamera);
        // float fogFactor = sampleLinearFog(minHeight, maxHeight, pixelHeight);
        
        // 使用视距计算雾的强度
        // float viewDistance = getViewDistance(positionWC);
        // float fogFactor = sampleLinearFog(minHeight, maxHeight, viewDistance);
        float fogFactor = sampleLinearHeightFog(1000.0, pixelHeight);
        // fogFactor *= visibility;

        myColor = mix(origncolor, vec4(fogColor, 1.0), fogFactor);
    }
    `;
  }
}
